﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Threading;

namespace SmartMathLibrary.Management.Performance
{
    /// <summary>
    /// This class is an abstract mainlayer for an suspend able thread.
    /// </summary>
    [Serializable]
    public abstract class AbstractThread
    {
        /// <summary>
        /// The thread for the execution.
        /// </summary>
        protected Thread thread;

        /// <summary>
        /// The suspend state.
        /// </summary>
        private bool suspendMode;

        /// <summary>
        /// The refresh rate.
        /// </summary>
        private readonly TimeSpan refreshRate;

        /// <summary>
        /// Initializes a new instance of the <see cref="AbstractThread"/> class.
        /// </summary>
        protected AbstractThread()
        {
            this.refreshRate = TimeSpan.FromMilliseconds(100);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="AbstractThread"/> class.
        /// </summary>
        /// <param name="refreshRate">The refresh rate for checking if the thread was set to resume state.</param>
        protected AbstractThread(TimeSpan refreshRate)
        {
            this.refreshRate = refreshRate;
        }

        /// <summary>
        /// Gets a value indicating the execution status of the current thread.
        /// </summary>
        /// <value>True if this thread has been started and has not terminated normally or aborted; otherwise, false.</value>
        public bool IsAlive
        {
            get { return this.thread.IsAlive; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not a thread is a background thread.
        /// </summary>
        /// <value>True if this thread is or is to become a background thread; otherwise, false.</value>
        public bool IsBackground
        {
            get { return this.thread.IsBackground; }
            set { this.thread.IsBackground = value; }
        }

        /// <summary>
        /// Gets a value indicating whether or not a thread belongs to the managed thread pool.
        /// </summary>
        /// <value>True if this thread belongs to the managed thread pool; otherwise, false.</value>
        public bool IsThreadPoolThread
        {
            get { return this.thread.IsThreadPoolThread; }
        }

        /// <summary>
        /// Gets or sets the name of the thread.
        /// </summary>
        /// <value>A string containing the name of the thread, or null if no name was set.</value>
        public string Name
        {
            get { return this.thread.Name; }
            set { this.thread.Name = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating the scheduling priority of a thread.
        /// </summary>
        /// <value>One of the System.Threading.ThreadPriority values. The default value is Normal.</value>
        public ThreadPriority Priority
        {
            get { return this.thread.Priority; }
            set { this.thread.Priority = value; }
        }

        /// <summary>
        /// Gets a value containing the states of the current thread.
        /// </summary>
        /// <value>One of the System.Threading.ThreadState values indicating the state of the current 
        /// thread. The initial value is Unstarted.</value>
        public ThreadState ThreadState
        {
            get { return this.thread.ThreadState; }
        }

        /// <summary>
        /// Causes the operating system to change the state of the current instance to 
        /// System.Threading.ThreadState.Running.
        /// </summary>
        public void Start()
        {
            this.thread.Start();
        }

        /// <summary>
        /// Causes the operating system to change the state of the current instance to 
        /// System.Threading.ThreadState.Running, and optionally supplies an object containing 
        /// data to be used by the method the thread executes.
        /// </summary>
        /// <param name="parameter">An object that contains data to be used by the method the thread 
        /// executes.</param>
        public void Start(object parameter)
        {
            this.thread.Start(parameter);
        }

        /// <summary>
        /// Raises a System.Threading.ThreadAbortException in the thread on which it is invoked, to 
        /// begin the process of terminating the thread. Calling this method usually terminates the thread.
        /// </summary>
        public void Abort()
        {
            this.thread.Abort();
        }

        /// <summary>
        /// Raises a System.Threading.ThreadAbortException in the thread on which it is invoked, to begin the 
        /// process of terminating the thread while also providing exception information about the thread 
        /// termination. Calling this method usually terminates the thread.
        /// </summary>
        /// <param name="stateInfo">An object that contains application-specific information, such as state, which 
        /// can be used by the thread being aborted.</param>
        public void Abort(object stateInfo)
        {
            this.thread.Abort(stateInfo);
        }

        /// <summary>
        /// Blocks the calling thread until a thread terminates, while continuing to perform standard COM and SendMessage 
        /// pumping.
        /// </summary>
        public void Join()
        {
            this.thread.Join();
        }

        /// <summary>
        /// Blocks the calling thread until a thread terminates or the specified time elapses, while continuing to perform 
        /// standard COM and SendMessage pumping.
        /// </summary>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait for the thread to terminate.</param>
        /// <returns>true if the thread has terminated; false if the thread has not terminated after the amount of 
        /// time specified by the millisecondsTimeout parameter has elapsed.</returns>
        public bool Join(int millisecondsTimeout)
        {
            return this.thread.Join(millisecondsTimeout);
        }

        /// <summary>
        /// Blocks the calling thread until a thread terminates or the specified time elapses, while continuing to
        /// perform standard COM and SendMessage pumping.
        /// </summary>
        /// <param name="timeout">A System.TimeSpan set to the amount of time to wait for the thread to terminate.</param>
        /// <returns>true if the thread has terminated; false if the thread has not terminated after the amount of 
        /// time specified by the millisecondsTimeout parameter has elapsed.</returns>
        public bool Join(TimeSpan timeout)
        {
            return this.thread.Join(timeout);
        }

        /// <summary>
        /// Suspends the current instance of the thread. Either the thread is already suspended, this method
        /// has no effect.
        /// </summary>
        public void Suspend()
        {
            this.suspendMode = true;
        }

        /// <summary>
        /// Suspends the thread for the specified milliseconds.
        /// </summary>
        /// <param name="millisecondsTimeout">The milliseconds, how long the thread should be suspend.</param>
        public static void Suspend(int millisecondsTimeout)
        {
            Thread.Sleep(millisecondsTimeout);
        }

        /// <summary>
        /// Checks the suspend state of the current thread.
        /// </summary>
        protected void CheckSuspend()
        {
            while (this.suspendMode)
            {
                Thread.Sleep(this.refreshRate);
            }
        }

        /// <summary>
        /// Resumes the current instance of the thread.
        /// </summary>
        public void Resume()
        {
            this.suspendMode = false;
        }

        /// <summary>
        /// Interrupts a thread that is in the WaitSleepJoin thread state.
        /// </summary>
        public void Interrupt()
        {
            this.thread.Interrupt();
        }

        /// <summary>
        /// Allocates an unnamed data slot on all the threads. For better performance, use fields 
        /// that are marked with the System.ThreadStaticAttribute attribute instead.
        /// </summary>
        /// <returns>A System.LocalDataStoreSlot.</returns>
        public static LocalDataStoreSlot AllocateDataSlot()
        {
            return Thread.AllocateDataSlot();
        }

        /// <summary>
        /// Allocates a named data slot on all threads. For better performance, use fields 
        /// that are marked with the System.ThreadStaticAttribute attribute instead.
        /// </summary>
        /// <param name="name">The name of the data slot to be allocated.</param>
        /// <returns>A System.LocalDataStoreSlot.</returns>
        public static LocalDataStoreSlot AllocateNamedDataSlot(string name)
        {
            return Thread.AllocateNamedDataSlot(name);
        }
    }
}